package com.tcheung.service;

import com.tcheung.entity.Document;
import com.tcheung.entity.TFEntity;
import com.tcheung.entity.TFIDFEntity;
import com.tcheung.utils.AppConstants;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * IndexService(单例)
 *
 * @author: zhangteng
 * @time: 2014/11/30 16:25
 */
public class IndexService {

    private static IndexService instance = null;

    public static IndexService getInstance(List<Document> documentList) {
        if (instance == null) {
            instance = new IndexService(documentList);
        }
        return instance;
    }

    /**
     * 此方必须在getInstance(List<Document> documentList)之后才能调用
     *
     * @return
     */
    public static IndexService getInstance() {
        return instance;
    }

    // 文档集的所有tf
    private List<TFEntity> tfEntityList = new ArrayList<TFEntity>();

    // 文档集的所有idf
    private List<TFIDFEntity> tfidfEntityList = new ArrayList<TFIDFEntity>();


    private Map<String, Integer> dfMap = new HashMap<String, Integer>();

    private Map<String, Double> idfMap = new HashMap<String, Double>();

    // 文档的索引map
    private Map<Integer, HashMap<String, TFIDFEntity>> docIndexes = new HashMap<Integer, HashMap<String, TFIDFEntity>>();

    private IndexService(List<Document> documentList) {
        init(documentList);
    }

    private void init(List<Document> documentList) {
        Integer df = 0;
        // 计算df值和tf值
        for (Document document : documentList) {
            Double maxTermCount = Double.valueOf(document.getMaxTermCount());
            for (TFEntity tfEntity : document.getTfEntityList()) {
                if (dfMap.containsKey(tfEntity.getKeyWord())) {
                    df = dfMap.get(tfEntity.getKeyWord());
                    dfMap.put(tfEntity.getKeyWord(), df + 1);
                } else {
                    dfMap.put(tfEntity.getKeyWord(), 1);
                }

                tfEntity.setTf(tfEntity.getTermCount() / maxTermCount);
                tfEntityList.add(tfEntity);
            }
        }
        // 计算idf值
        double documentSize = documentList.size() * 1.0;
        for (Map.Entry<String, Integer> entry : dfMap.entrySet()) {
            Double idf = Math.log(documentSize / entry.getValue());
            idfMap.put(entry.getKey(), idf);
        }

        // 计算tf*idf
        for (TFEntity tfEntity : tfEntityList) {
            // TFIDFEntity tfidfEntity = new TFIDFEntity(tfEntity.getDocNum(), tfEntity.getKeyWord(), tfEntity.getTf() *
            //        idfMap.get(tfEntity.getKeyWord()));
            Double tfidf = tfEntity.getTf() * idfMap.get(tfEntity.getKeyWord());
            // System.out.println(tfEntity.getKeyWord() + " " + tfEntity.getTf() + " " + idfMap.get(tfEntity.getKeyWord()) + " " + tfidf);
            if (tfidf.compareTo(AppConstants.minTFIDFWeight) > 0) {
                TFIDFEntity tfidfEntity = new TFIDFEntity(tfEntity.getDocNum(), tfEntity.getKeyWord(), tfidf);
                tfidfEntityList.add(tfidfEntity);
            }
        }
        // 由于去掉了一些词，所以需要重新构造idfMap供后面的程序使用
        Map<String, Double> newIdfMap = new HashMap<String, Double>();
        for (TFIDFEntity tfidfEntity : tfidfEntityList) {
            newIdfMap.put(tfidfEntity.getKeyWord(), idfMap.get(tfidfEntity.getKeyWord()));
        }
        idfMap = newIdfMap;
        generateDocIndexes();
    }

    /**
     * 生成文档的索引
     */
    private void generateDocIndexes() {
        for (TFIDFEntity tfidfEntity : tfidfEntityList) {
            int docNum = tfidfEntity.getDocNum();
            HashMap<String, TFIDFEntity> hashMap;
            if (docIndexes.containsKey(docNum)) {
                hashMap = docIndexes.get(docNum);
            } else {
                hashMap = new HashMap<String, TFIDFEntity>();
            }
            hashMap.put(tfidfEntity.getKeyWord(), tfidfEntity);
            docIndexes.put(tfidfEntity.getDocNum(), hashMap);
        }
    }

    /**
     * 根据文档号获取文档的索引
     *
     * @param docNum
     * @return
     */
    public Map<String, TFIDFEntity> getDocIndexesByDocNum(int docNum) {
        return docIndexes.get(docNum);
    }

    public Double getIdfByTerm(String term) {
        if (idfMap.containsKey(term)) {
            return idfMap.get(term);
        }
        return null;
    }

    public List<TFEntity> getTfEntityList() {
        return tfEntityList;
    }

    public void setTfEntityList(List<TFEntity> tfEntityList) {
        this.tfEntityList = tfEntityList;
    }

    public List<TFIDFEntity> getTfidfEntityList() {
        return tfidfEntityList;
    }

    public void setTfidfEntityList(List<TFIDFEntity> tfidfEntityList) {
        this.tfidfEntityList = tfidfEntityList;
    }

    public Map<String, Double> getIdfMap() {
        return idfMap;
    }
}
